home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / nr4.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  23KB  |  850 lines

  1. /* net/rom level 4 (transport) protocol implementation
  2.  * Copyright 1989 by Daniel M. Frank, W9NK.  Permission granted for
  3.  * non-commercial distribution only.
  4.  * Ported to NOS by SM0RGV, 890525.
  5.  * Inactivity timeout by WG7J, 920325
  6.  */
  7.  
  8. #include <stdio.h>
  9. #include "global.h"
  10. #include "config.h"
  11. #include "mbuf.h"
  12. #include "timer.h"
  13. #include "ax25.h"
  14. #include "lapb.h"
  15. #include "netrom.h"
  16. #include "nr4.h"
  17. #include "cmdparse.h"
  18. #include <ctype.h>
  19.  
  20. #undef NR4DEBUG
  21.  
  22. /* Globals: */
  23.  
  24. /* The circuit table */
  25.  
  26. struct nr4circp Nr4circuits[NR4MAXCIRC];
  27.  
  28. /* Various limits */
  29.  
  30. unsigned short Nr4window = 4;           /* Max window to negotiate */
  31. unsigned short Nr4retries = 10; /* Max retries */
  32. unsigned short Nr4qlimit = 2048;        /* Max bytes on receive queue */
  33.  
  34. /* Timers */
  35.  
  36. int32 Nr4irtt = 45000;          /* Initial round trip time */
  37. int32 Nr4acktime = 3000;                /* ACK delay timer */
  38. int32 Nr4choketime = 180000;    /* CHOKEd state timeout */
  39.  
  40. static void nr4ackours __ARGS((struct nr4cb *, unsigned, int));
  41. static void nr4choke __ARGS((struct nr4cb *));
  42. static void nr4gotnak __ARGS((struct nr4cb *, unsigned));
  43. static void nr4rframe __ARGS((struct nr4cb *, unsigned, struct mbuf *));
  44.  
  45. #ifdef NR4TDISC
  46.  
  47. int32 Nr4tdiscinit = 0;          /* Inactivity timeout - WG7J */
  48.  
  49. int
  50. #ifdef PROTOTYPES
  51. donr4tdisc(int argc,char **argv,void *p)
  52. #else
  53. donr4tdisc(argc,argv,p)
  54. int argc;
  55. char *argv[];
  56. void *p;
  57. #endif
  58. {
  59.     return setlong(&Nr4tdiscinit,"NR4 redundancy timer (sec)",argc,argv);
  60. }
  61.  
  62. /* Changes are if we reachs this, with 'normal' values of tdisc,
  63.  * the other end has already timed  and retried out.
  64.  * So simply reset the control block - WG7J
  65.  */
  66.  
  67. #ifdef notdef
  68. /* This doesn't seem to catch ALL cases,
  69.  * if someone can fix this, please let me know - WG7J
  70.  */
  71. void
  72. nr4_redundant(cb)
  73. struct nr4cb *cb;
  74. {
  75.     struct nr4hdr hdr;
  76.  
  77.     switch(cb->state){
  78.     case NR4STCPEND:
  79.     case NR4STCON:
  80.     /* Format disconnect request packet */
  81.     hdr.opcode = NR4OPDISRQ ;
  82.     hdr.yourindex = cb->yournum ;
  83.     hdr.yourid = cb->yourid ;
  84.  
  85.     /* Set and start timer */
  86.     cb->cdtries = 1 ;
  87.     set_timer(&cb->tcd,2 * cb->srtt);
  88.     cb->tcd.func = nr4cdtimeout ;
  89.     cb->tcd.arg = cb ;
  90.     start_timer(&cb->tcd) ;
  91.  
  92.     /* Send packet */
  93.     nr4sframe(cb->remote.node, &hdr, NULLBUF) ;
  94.  
  95.     /* Signal state change.  nr4state will take care of stopping */
  96.     /* the appropriate timers and resetting window pointers. */
  97.     nr4state(cb, NR4STDPEND) ;
  98.         break;
  99.     }
  100.  
  101. }
  102. #endif
  103.  
  104. #endif /* NR4TDISC */
  105.  
  106.  
  107.  
  108. /* This function is called when a net/rom layer four frame */
  109. /* is discovered inside a datagram addressed to us */
  110.  
  111. void
  112. nr4input(hdr,bp)
  113. struct nr4hdr *hdr;
  114. struct mbuf *bp;
  115. {
  116.     struct nr4hdr rhdr;
  117.     struct nr4cb *cb, *cb2;
  118.     int op;
  119.     unsigned window;
  120.     int acceptc;            /* indicates that connection should be accepted */
  121.     int newconn;            /* indicates that this is a new incoming */
  122.                         /* connection.  You'll see. */
  123.     int gotchoke;           /* The choke flag was set in this packet */
  124.     int i;
  125.     long t;
  126.     
  127.     op = hdr->opcode & NR4OPCODE;   /* Mask off flags */
  128.     
  129.     if(op == NR4OPCONRQ){                   /* process connect request first */
  130.         acceptc = 1;
  131.         newconn = 0;
  132.  
  133.         /* These fields are sent regardless of success */
  134.         rhdr.yourindex = hdr->u.conreq.myindex;
  135.         rhdr.yourid = hdr->u.conreq.myid;
  136.  
  137.         /* Check to see if we have already received a connect */
  138.         /* request for this circuit. */
  139.         if((cb = match_n4circ(hdr->u.conreq.myindex,
  140.          hdr->u.conreq.myid,hdr->u.conreq.user,hdr->u.conreq.node))
  141.          == NULLNR4CB){ /* No existing circuit if NULL */
  142.         
  143. #ifndef UNIX
  144.         /* If low on memory, don't accept - WG7J */
  145.         if(availmem() < Memthresh)
  146.         acceptc = 0;
  147.         else {
  148. #endif
  149.         /* Try to get a new circuit */
  150.         if((cb = new_n4circ()) == NULLNR4CB)
  151.             acceptc = 0;
  152.         /* See if we have any listening sockets */
  153.         for(i = 0; i < NR4MAXCIRC; i++){
  154.             if((cb2 = Nr4circuits[i].ccb) == NULLNR4CB)
  155.             continue;/* not an open circuit */
  156.             if(cb2->state == NR4STLISTEN)
  157.             /* A listener was found */
  158.             break;
  159.         }
  160.         if(i == NR4MAXCIRC){ /* We are refusing connects */
  161.             acceptc = 0;
  162.             free_n4circ(cb);
  163.         }
  164.         if(acceptc){
  165.             /* Load the listeners settings */
  166.             cb->clone = cb2->clone;
  167.             cb->user = cb2->user;
  168.             cb->t_upcall = cb2->t_upcall;
  169.             cb->s_upcall = cb2->s_upcall;
  170.             cb->r_upcall = cb2->r_upcall;
  171.             ASSIGN(cb->local,cb2->local);
  172.  
  173.             /* Window is set to min of the offered
  174.              * and local windows
  175.              */
  176.             window = hdr->u.conreq.window > Nr4window ?
  177.                 Nr4window : hdr->u.conreq.window;
  178.  
  179.             if(init_nr4window(cb, window) == -1){
  180.             free_n4circ(cb);
  181.             acceptc = 0;
  182.             } else {
  183.             /* Set up control block */
  184.             cb->yournum = hdr->u.conreq.myindex;
  185.             cb->yourid = hdr->u.conreq.myid;
  186.             memcpy(cb->remote.user,
  187.                 hdr->u.conreq.user,AXALEN);
  188.             memcpy(cb->remote.node,
  189.                 hdr->u.conreq.node,AXALEN);
  190.             /* Default round trip time */
  191.             cb->srtt = Nr4irtt;
  192.             /* set up timers, window pointers */
  193.             nr4defaults(cb);
  194.             cb->state = NR4STDISC;
  195.             newconn = 1;
  196.             } /* End if window successfully allocated */
  197.         }   /* End if new circuit available */
  198. #ifndef UNIX
  199.         } /* End of memory-low else */
  200. #endif
  201.      } /* End if no existing circuit matching parameters */
  202.  
  203.         /* Now set up response */
  204.         if(!acceptc){
  205.             rhdr.opcode = NR4OPCONAK | NR4CHOKE;/* choke means reject */
  206.             rhdr.u.conack.myindex = 0;
  207.             rhdr.u.conack.myid = 0;
  208.             rhdr.u.conack.window = 0;
  209.         } else {
  210.             rhdr.opcode = NR4OPCONAK;
  211.             rhdr.u.conack.myindex = cb->mynum;
  212.             rhdr.u.conack.myid = cb->myid;
  213.             rhdr.u.conack.window = cb->window;
  214.         }
  215.         nr4sframe(hdr->u.conreq.node, &rhdr, NULLBUF);
  216.  
  217.         /* Why, you ask, do we wait until now for the state change
  218.          * upcall?  Well, it's like this:  if the state change triggers
  219.          * something like the mailbox to send its banner, the banner
  220.          * would have gone out *before* the conn ack if we'd done this
  221.          * in the code above.  This is what happens when you don't plan
  222.          * too well.  Learn from my mistakes :-)
  223.          */
  224.         if(newconn)
  225.             nr4state(cb, NR4STCON);/* connected (no 3-way handshake) */
  226.             
  227.         free_p(bp);
  228.         return;
  229.     } /* end connect request code */
  230.  
  231.     /* validate circuit number */
  232.     if((cb = get_n4circ(hdr->yourindex, hdr->yourid)) == NULLNR4CB){
  233.         free_p(bp);
  234.         return;
  235.     }
  236.  
  237.     /* Check for choke flag */
  238.     if(hdr->opcode & NR4CHOKE)
  239.         gotchoke = 1;
  240.     else
  241.         gotchoke = 0;
  242.     
  243.     /* Here's where the interesting stuff gets done */
  244.     switch(cb->state){
  245.     case NR4STCPEND:
  246.         switch(op){
  247.         case NR4OPCONAK:
  248.             /* Save the round trip time for later use */
  249.             t = dur_timer(&cb->tcd) - read_timer(&cb->tcd);
  250.             stop_timer(&cb->tcd);
  251.             if(gotchoke){           /* connect rejected */
  252.                 cb->dreason = NR4RREFUSED;
  253.                 nr4state(cb, NR4STDISC);
  254.                 break;
  255.             }
  256.             cb->yournum = hdr->u.conack.myindex;
  257.             cb->yourid = hdr->u.conack.myid;
  258.             window = hdr->u.conack.window > Nr4window ?
  259.                      Nr4window : hdr->u.conack.window;
  260.  
  261.             if(init_nr4window(cb, window) == -1){
  262.                 cb->dreason = NR4RRESET;
  263.                 nr4state(cb, NR4STDISC);
  264.             } else {
  265.                 nr4defaults(cb);        /* set up timers, window pointers */
  266.                 
  267.                 if(cb->cdtries == 1)    /* No retries */
  268.                     /* Use measured rtt */
  269.                     cb->srtt = t;
  270.                 else
  271.                     /* else use default */
  272.                     cb->srtt = Nr4irtt;
  273.                     
  274.                 nr4state(cb, NR4STCON);
  275.                 nr4output(cb);          /* start sending anything on the txq */
  276.             }
  277.             break;
  278.         default:
  279.             /* We can't respond to anything else without
  280.              * Their ID and index
  281.              */
  282.             free_p(bp);
  283.             return;
  284.         }
  285.         break;
  286.     case NR4STCON:
  287.         switch(op){
  288.         case NR4OPDISRQ:
  289.             /* format reply packet */
  290.             rhdr.opcode = NR4OPDISAK;
  291.             rhdr.yourindex = cb->yournum;
  292.             rhdr.yourid = cb->yourid;
  293.             nr4sframe(cb->remote.node,&rhdr,NULLBUF);
  294.             cb->dreason = NR4RREMOTE;
  295.             nr4state(cb, NR4STDISC);
  296.             break;
  297.           case NR4OPINFO:
  298.             /* Do receive frame processing */
  299.             nr4rframe(cb, (unsigned)hdr->u.info.txseq, bp);
  300.  
  301.             /* Reset the choke flag if no longer choked.  Processing
  302.              * the ACK will kick things off again.
  303.              */
  304.             if(cb->choked && !gotchoke){
  305.                 stop_timer(&cb->tchoke);
  306.                 cb->choked = 0;
  307.             }
  308.                 
  309.             /* We delay processing the receive sequence number until
  310.              * now, because the ACK might pull more off the txq and send
  311.              * it, and we want the implied ACK in those frames to be right
  312.              *
  313.              * Only process NAKs if the choke flag is off.  It appears
  314.              * that NAKs should never be sent with choke on, by the way,
  315.              * but you never know, considering that there is no official
  316.              * standard for this protocol
  317.              */
  318.             if(hdr->opcode & NR4NAK && !gotchoke)
  319.                 nr4gotnak(cb, (unsigned)hdr->u.info.rxseq);
  320.  
  321.             /* We always do ACK processing, too, since the NAK of one
  322.              * packet may be the implied ACK of another.  The gotchoke
  323.              * flag is used to prevent sending any new frames, since
  324.              * we are just going to purge them next anyway if this is
  325.              * the first time we've seen the choke flag.  If we are
  326.              * already choked, this call will return immediately.
  327.              */
  328.             nr4ackours(cb, (unsigned)hdr->u.info.rxseq, gotchoke);
  329.  
  330.             /* If we haven't seen the choke flag before, purge the
  331.              * send window and set the timer and the flag.
  332.              */
  333.             if(!cb->choked && gotchoke)
  334.                 nr4choke(cb);
  335.             break;
  336.           case NR4OPACK:
  337.             if(cb->choked && !gotchoke){
  338.                 /* clear choke if appropriate */
  339.                 stop_timer(&cb->tchoke);
  340.                 cb->choked = 0;
  341.             }       
  342.             if(hdr->opcode & NR4NAK && !gotchoke)
  343.                 nr4gotnak(cb, (unsigned)hdr->u.ack.rxseq);        /* process NAKs */
  344.                 
  345.             nr4ackours(cb, (unsigned)hdr->u.ack.rxseq, gotchoke); /* and ACKs */
  346.  
  347.             if(!cb->choked && gotchoke)     /* First choke seen */
  348.                 nr4choke(cb);           /* Set choke status */
  349.  
  350.             break;
  351.         }
  352.         break;
  353.     case NR4STDPEND:
  354.         switch(op){
  355.         case NR4OPDISAK:
  356.             cb->dreason = NR4RNORMAL;
  357.             nr4state(cb, NR4STDISC);
  358.             break;
  359.         case NR4OPINFO:
  360.             /* We can still do receive frame processing until
  361.              * the disconnect acknowledge arrives, but we won't
  362.              * bother to process ACKs, since we've flushed our
  363.              * transmit buffers and queue already.
  364.              */
  365.             nr4rframe(cb, (unsigned)hdr->u.info.txseq, bp);
  366.             break;
  367.         }
  368.     }       /* End switch(state) */
  369. }
  370.  
  371.  
  372. /* Send a net/rom layer 4 frame.  bp should be NULLBUF unless the frame
  373.  * type is info.
  374.  */
  375. void
  376. nr4sframe(dest, hdr, bp)
  377. char *dest;
  378. struct nr4hdr *hdr;
  379. struct mbuf *bp;
  380. {
  381.     struct mbuf *n4b;
  382.  
  383.     if((n4b = htonnr4(hdr)) == NULLBUF){
  384.         free_p(bp);
  385.         return;
  386.     } else {
  387.         append(&n4b, bp);
  388.         nr3output(dest, n4b);
  389.     }
  390. }
  391.  
  392. /* Receive frame processing */
  393. static void
  394. nr4rframe(cb, rxseq, bp)
  395. struct nr4cb *cb;
  396. unsigned rxseq;
  397. struct mbuf *bp;
  398. {
  399.     struct nr4hdr rhdr;
  400.     unsigned window = cb->window;
  401.     unsigned rxbuf = rxseq % window;
  402.     unsigned newdata = 0;           /* whether to upcall */
  403.  
  404. #ifdef NR4DEBUG
  405.     printf("Processing received info\n");
  406. #endif
  407.  
  408. #ifdef NR4TDISC
  409.     /* We received data, reset the inactivity timer - WG7J */
  410.     start_timer(&cb->tdisc);
  411. #endif
  412.  
  413.     /* If we're choked, just reset the ACK timer to blast out
  414.      * another CHOKE indication after the ackdelay
  415.      */
  416.     if(cb->qfull){
  417.         start_timer(&cb->tack);
  418.         return;
  419.     }
  420.     
  421.     /* If frame is out of sequence, it is either due to a lost frame
  422.      * or a retransmission of one seen earlier.  We do not want to NAK
  423.      * the latter, as the far end would see this as a requirement to
  424.      * retransmit the expected frame, which is probably already in the
  425.      * pipeline.  This in turn would cause another out-of-sequence
  426.      * condition, another NAK, and the process would repeat indefinitely.
  427.      * Therefore, if the frame is out-of-sequence, but within the last
  428.      * 'n' frames by sequence number ('n' being the window size), just
  429.      * accept it and discard it.  Else, NAK it if we haven't already.
  430.      *      (Modified by Rob Stampfli, kd8wk, 9 Jan 1990)
  431.      */
  432.     if(rxseq != cb->rxpected && !cb->naksent){
  433. #ifdef NR4DEBUG
  434.         printf("Frame out of sequence -- expected %u, got %u.\n",
  435.                cb->rxpected, rxseq);
  436. #endif                          
  437.         if(nr4between((unsigned)cb->rxpected,
  438.            (rxseq + window) & NR4SEQMASK, (unsigned)cb->rxpastwin))
  439.             /* just a repeat of old frame -- queue ack for
  440.              * expected frame
  441.              */
  442.             start_timer(&cb->tack);
  443.         else {                  /* really bogus -- a NAKable frame */
  444.             rhdr.opcode = NR4OPACK | NR4NAK;
  445.             rhdr.yourindex = cb->yournum;
  446.             rhdr.yourid = cb->yourid;
  447.             rhdr.u.ack.rxseq = cb->rxpected;
  448.             nr4sframe(cb->remote.node,&rhdr,NULLBUF);
  449.         
  450.             /* Now make sure we don't send any more of these until
  451.              * we see some good data.  Otherwise full window
  452.              * retransmissions would result in a flurry of NAKs
  453.              */
  454.         
  455.             cb->naksent = 1;
  456.         }
  457.     }
  458.             
  459.     /* If this is a new frame, within the window, buffer it,
  460.      * then see what we can deliver
  461.      */
  462.     if(nr4between((unsigned)cb->rxpected,rxseq,(unsigned)cb->rxpastwin)
  463.         && !cb->rxbufs[rxbuf].occupied){
  464. #ifdef NR4DEBUG
  465.         printf("Frame within window\n");
  466. #endif
  467.         cb->rxbufs[rxbuf].occupied = 1;
  468.         cb->rxbufs[rxbuf].data = bp;
  469.                 
  470.         for(rxbuf = cb->rxpected % window; cb->rxbufs[rxbuf].occupied;
  471.              rxbuf = cb->rxpected % window){
  472. #ifdef NR4DEBUG
  473.             printf("Removing frame from buffer %d\n", rxbuf);
  474. #endif
  475.             newdata = 1;
  476.             cb->rxbufs[rxbuf].occupied = 0;
  477.             append(&cb->rxq,cb->rxbufs[rxbuf].data);
  478.             cb->rxbufs[rxbuf].data = NULLBUF;
  479.             cb->rxpected = (cb->rxpected + 1) & NR4SEQMASK;
  480.             cb->rxpastwin = (cb->rxpastwin + 1) & NR4SEQMASK;
  481.         }
  482.         if(newdata){
  483.             cb->naksent = 0;        /* OK to send NAKs again */
  484.             if(cb->r_upcall != NULLVFP((struct nr4cb*,int16)))
  485.                 (*cb->r_upcall)(cb,len_p(cb->rxq));
  486.  
  487.             /* Now that our upcall has had a shot at the queue, */
  488.             /* see if it's past the queue length limit.  If so, */
  489.             /* go into choked mode (i.e. flow controlled). */
  490.  
  491.             if(len_p(cb->rxq) > Nr4qlimit){
  492.                 cb->qfull = 1;
  493.                 nr4ackit((void *)cb);   /* Tell `em right away */
  494.             } else
  495.                 start_timer(&cb->tack);
  496.         }
  497.     } else  /* It's out of the window or we've seen it already */
  498.         free_p(bp);
  499. }
  500.  
  501.  
  502. /* Send the transmit buffer whose sequence number is seq */
  503. void
  504. nr4sbuf(cb, seq)
  505. struct nr4cb *cb;
  506. unsigned seq;
  507. {
  508.     struct nr4hdr hdr;
  509.     struct mbuf *bufbp, *bp;
  510.     unsigned bufnum = seq % cb->window;
  511.     struct timer *t;
  512.     
  513.     /* sanity check */
  514.     if(bufnum >= cb->window){
  515. #ifdef NRDEBUG
  516.         printf("sbuf: buffer number %u beyond window\n",bufnum);
  517. #endif
  518.         return;
  519.     }
  520.  
  521.     /* Stop the ACK timer, since our sending of the frame is
  522.      * an implied ACK.
  523.      */
  524.     stop_timer(&cb->tack);
  525.     
  526.     /* Duplicate the mbuf, since we have to keep it around
  527.      * until it is acknowledged
  528.      */
  529.     bufbp = cb->txbufs[bufnum].data;
  530.  
  531.     /* Notice that we use copy_p instead of dup_p.  This is because
  532.      * a frame can still be sitting on the AX.25 send queue when it
  533.      * get acknowledged, and we don't want to deallocate its data
  534.      * before it gets sent!
  535.      */
  536.     if((bp = copy_p(bufbp, len_p(bufbp))) == NULLBUF){
  537.         free_mbuf(bp);
  538.         return;
  539.     }
  540.  
  541.     /* Prepare the header */
  542.     if(cb->qfull)                           /* are we choked? */
  543.         hdr.opcode = NR4OPINFO | NR4CHOKE;
  544.     else
  545.         hdr.opcode = NR4OPINFO;
  546.     hdr.yourindex = cb->yournum;
  547.     hdr.yourid = cb->yourid;
  548.     hdr.u.info.txseq = (unsigned char)(seq & NR4SEQMASK);
  549.     hdr.u.info.rxseq = cb->rxpected;
  550.     
  551.     /* Send the frame, then set and start the timer */
  552.     nr4sframe(cb->remote.node, &hdr, bp);
  553.  
  554.     t = &cb->txbufs[bufnum].tretry;
  555.     set_timer(t, (1 << cb->blevel) * (4 * cb->mdev + cb->srtt));
  556.     start_timer(t);
  557. }
  558.  
  559. /* Check to see if any of our frames have been ACKed */
  560.  
  561. static void
  562. nr4ackours(cb, seq, gotchoke)
  563. struct nr4cb *cb;
  564. unsigned seq;
  565. int gotchoke;   /* The choke flag is set in the received frame */
  566. {
  567.     unsigned txbuf;
  568.     struct timer *t;
  569.     
  570.     /* If we are choked, there is nothing in the send window
  571.      * by definition, so we can just return.
  572.      */
  573.     if(cb->choked)
  574.         return;
  575.         
  576.     /* Adjust seq to point to the frame being ACK'd, not the one
  577.      * beyond it, which is how it arrives.
  578.      */
  579.     seq = (seq - 1) & NR4SEQMASK;
  580.  
  581.     /* Free up all the ack'd frames, and adjust the round trip
  582.      * timing stuff
  583.      */
  584.     while (nr4between((unsigned)cb->ackxpected, seq, (unsigned)cb->nextosend)){
  585. #ifdef NR4DEBUG
  586.         printf("Sequence # %u acknowledged\n", seq);
  587. #endif
  588.         cb->nbuffered--;
  589.         txbuf = cb->ackxpected % cb->window;
  590.         free_mbuf(cb->txbufs[txbuf].data);
  591.         cb->txbufs[txbuf].data = NULLBUF;
  592.         cb->ackxpected = (cb->ackxpected + 1) & NR4SEQMASK;
  593.  
  594.         /* Round trip time estimation, cribbed from TCP */
  595.         if(cb->txbufs[txbuf].retries == 0){
  596.             /* We only sent this one once */
  597.             int32 rtt;
  598.             int32 abserr;
  599.  
  600.             t = &cb->txbufs[txbuf].tretry;
  601.             /* get our rtt in msec */
  602.             rtt = dur_timer(t) - read_timer(t);
  603.             abserr = (rtt > cb->srtt) ? rtt - cb->srtt : cb->srtt - rtt;
  604.             cb->srtt = (cb->srtt * 7 + rtt) >> 3;
  605.             cb->mdev = (cb->mdev * 3 + abserr) >> 2;
  606.  
  607.             /* Reset the backoff level */
  608.             cb->blevel = 0;
  609.         }
  610.         stop_timer(&cb->txbufs[txbuf].tretry);
  611.     }       
  612.     /* Now we recalculate tmax, the maximum number of retries for
  613.      * any frame in the window.  tmax is used as a baseline to
  614.      * determine when the window has reached a new high in retries.
  615.      * We don't want to increment blevel for every frame that times
  616.      * out, since that would lead to us backing off too fast when
  617.      * all the frame timers expired at around the same time.
  618.      */
  619.     cb->txmax = 0;
  620.     
  621.     for(seq = cb->ackxpected;
  622.          nr4between((unsigned)cb->ackxpected, seq, (unsigned)cb->nextosend);
  623.          seq = (seq + 1) & NR4SEQMASK)
  624.         if(cb->txbufs[seq % cb->window].retries > cb->txmax)
  625.             cb->txmax = cb->txbufs[seq % cb->window].retries;
  626.  
  627.     /* This is kind of a hack.  This function is called under
  628.      * three different conditions:  either we are choked, in
  629.      * which case we return immediately, or we are not choked,
  630.      * in which case we proceed normally to keep the send
  631.      * window full, or we have seen the choke flag for the first
  632.      * time.  In the last case, gotchoke is true while cb->choked
  633.      * is false.  We want to process any acknowledgments of existing
  634.      * frames in the send window before we purge it, while at the
  635.      * same time we don't want to take anything else off the txq
  636.      * or send it out.  So, in the third case we listed, we return
  637.      * now since we've processed the ACK.
  638.      */
  639.     
  640.     if(gotchoke)
  641.         return;
  642.         
  643.     nr4output(cb);                  /* yank stuff off txq and send it */
  644.  
  645.     /* At this point, either the send window is full, or
  646.      * nr4output() didn't find enough on the txq to fill it.
  647.      * If the window is not full, then the txq must be empty,
  648.      * and we'll make a tx upcall
  649.      */
  650.     if(cb->nbuffered < cb->window && cb->t_upcall != NULLVFP((struct nr4cb*,int16)))
  651.         (*cb->t_upcall)(cb, (int16)((cb->window - cb->nbuffered) * NR4MAXINFO));
  652.  
  653. }
  654.  
  655.  
  656. /* If the send window is open and there are frames on the txq,
  657.  * move as many as possible to the transmit buffers and send them.
  658.  * Return the number of frames sent.
  659.  */
  660. int
  661. nr4output(cb)
  662. struct nr4cb *cb;
  663. {
  664.     int numq, i;
  665.     struct mbuf *bp;
  666.     struct nr4txbuf *tp;
  667.  
  668.     /* Are we in the proper state? */
  669.     if(cb->state != NR4STCON || cb->choked)
  670.         return 0;               /* No sending if not connected */
  671.                     /* or if choked */
  672.         
  673.     /* See if the window is open */
  674.     if(cb->nbuffered >= cb->window)
  675.         return 0;
  676.  
  677.     numq = len_q(cb->txq);
  678.     
  679. #ifdef NR4DEBUG
  680.     printf("nr4output: %d packets on txq\n", numq);
  681. #endif
  682.     
  683.     for(i = 0; i < numq; i++){
  684.         bp = dequeue(&cb->txq);
  685. #ifdef NR4DEBUG
  686.         if(len_p(bp) > NR4MAXINFO){     /* should be checked higher up */
  687.             printf("Upper layers queued too big a buffer\n");
  688.             continue;
  689.         }
  690. #endif
  691.         /* Set up and send buffer */
  692.         tp = &cb->txbufs[cb->nextosend % cb->window];
  693.         tp->retries = 0;
  694.         tp->data = bp;
  695.         nr4sbuf(cb, (unsigned)cb->nextosend);
  696.  
  697.         /* Update window and buffered count */
  698.         cb->nextosend = (cb->nextosend + 1) & NR4SEQMASK;
  699.         if(++cb->nbuffered >= cb->window)
  700.             break;
  701.     }
  702.     return i;               
  703. }
  704.  
  705. void
  706. nr4state(cb, newstate)
  707. struct nr4cb *cb;
  708. int newstate;
  709. {
  710.     int i;
  711.     int oldstate = cb->state;
  712.     
  713.     cb->state = newstate;
  714.  
  715.     switch(cb->state){
  716. #ifdef NR4TDISC
  717.     case NR4STCON:
  718.     /* We're connected now, start inactivity timer - WG7J */
  719.     set_timer(&cb->tdisc,Nr4tdiscinit*1000L);
  720.     /*
  721.         cb->tdisc.func = nr4_redundant ;
  722.      * Second try; the call to nr4_redundant() (see above)
  723.      * doesn't seem to catch ALL situations.
  724.      * Changes are if we reachs this, with 'normal' values of tdisc,
  725.      * the other end has already timed out and retried out.
  726.      * So simply reset the control block - WG7J
  727.      */
  728.     cb->tdisc.func = (void (*)__ARGS((void*))) reset_nr4;
  729.     cb->tdisc.arg = cb ;
  730.     start_timer(&cb->tdisc) ;
  731.     break;
  732. #endif
  733.     case NR4STDPEND:
  734.         stop_timer(&cb->tchoke);
  735. #ifdef NR4TDISC
  736.     start_timer(&cb->tdisc);
  737. #endif
  738.  
  739.         /* When we request a disconnect, we lose the contents of
  740.          * our transmit queue and buffers, but we retain our ability
  741.          * to receive any packets in transit until a disconnect
  742.          * acknowledge arrives
  743.          */
  744.         free_q(&cb->txq);
  745.         
  746.         for(i = 0; i < cb->window; i++){
  747.             free_mbuf(cb->txbufs[i].data);
  748.             cb->txbufs[i].data = NULLBUF;
  749.             stop_timer(&cb->txbufs[i].tretry);
  750.         }
  751.         
  752.         /* Tidy up stats: roll the top window pointer back
  753.          * and reset nbuffered to reflect this.  Not really
  754.          * necessary, but leads to a bit more truth telling
  755.          * in the status displays.
  756.          */
  757.         cb->nextosend = cb->ackxpected;
  758.         cb->nbuffered = 0;
  759.         break;
  760.       case NR4STDISC:
  761.         stop_timer(&cb->tchoke);
  762.         stop_timer(&cb->tack);
  763.         stop_timer(&cb->tcd);
  764. #ifdef NR4TDISC
  765.     stop_timer(&cb->tdisc);
  766. #endif
  767.  
  768.         /* We don't clear the rxq, since the state change upcall
  769.          * may pull something off of it at the last minute.
  770.          */
  771.         free_q(&cb->txq);
  772.  
  773.         /* The following loop will only be executed if the
  774.          * window was set, since when the control block is
  775.          * calloc'd the window field gets a 0 in it.  This
  776.          * protects us from dereferencing an unallocated
  777.          * window buffer pointer
  778.          */
  779.         for(i = 0; i < cb->window; i++){
  780.             free_mbuf(cb->rxbufs[i].data);
  781.             cb->rxbufs[i].data = NULLBUF;
  782.             free_mbuf(cb->txbufs[i].data);
  783.             cb->txbufs[i].data = NULLBUF;
  784.             stop_timer(&cb->txbufs[i].tretry);
  785.         }
  786.         break;
  787.     }
  788.  
  789.     if(oldstate != newstate && cb->s_upcall != NULLVFP((struct nr4cb*,int,int)))
  790.         (*cb->s_upcall)(cb, oldstate, newstate);
  791.  
  792.     /* We take responsibility for deleting the circuit
  793.      * descriptor.  Don't do this anywhere else!
  794.      */
  795.     if(newstate == NR4STDISC)
  796.         free_n4circ(cb);
  797. }
  798.  
  799. /* Process NAKs.  seq indicates the next frame expected by the
  800.  * NAK'ing station.
  801.  */
  802.  
  803. static void
  804. nr4gotnak(cb, seq)
  805. struct nr4cb *cb;
  806. unsigned seq;
  807. {
  808.     if(nr4between((unsigned)cb->ackxpected, seq, (unsigned)cb->nextosend))
  809.         nr4sbuf(cb, seq);
  810. }
  811.  
  812.  
  813. /* This is called when we first get a CHOKE indication from the
  814.  * remote.  It purges the send window and sets the choke timer.
  815.  */
  816.  
  817. static void
  818. nr4choke(cb)
  819. struct nr4cb *cb;
  820. {
  821.     unsigned seq;
  822.     struct mbuf *q, *bp;
  823.     struct nr4txbuf *t;
  824.  
  825.     q = cb->txq;
  826.  
  827.     /* We purge the send window, returning the buffers to the
  828.      * txq in the proper order.
  829.      */
  830.     for(seq = (cb->nextosend - 1) & NR4SEQMASK;
  831.          nr4between((unsigned)cb->ackxpected, seq, (unsigned)cb->nextosend);
  832.          seq = (seq - 1) & NR4SEQMASK){
  833.  
  834.         t = &cb->txbufs[seq % cb->window];
  835.         stop_timer(&t->tretry);
  836.         bp = t->data;
  837.         t->data = NULLBUF;
  838.         enqueue(&bp, q);        /* prepend this packet to the queue */
  839.         q = bp;
  840.      }
  841.  
  842.     cb->nextosend = cb->ackxpected; /* close the window */
  843.     cb->nbuffered = 0;              /* nothing in the window */
  844.     cb->txq = q;                    /* Replace the txq with the one that has */
  845.                     /* the purged packets prepended */
  846.     cb->choked = 1;         /* Set the choked flag */
  847.  
  848.     start_timer(&cb->tchoke);
  849. }
  850.